package com.cndw.kungfu.model.pvp.war;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentSkipListMap;

import com.cndw.kungfu.config.Constants;
import com.cndw.kungfu.ext.LanguageLib;
import com.cndw.kungfu.ext.LogUtil;
import com.cndw.kungfu.ext.NumberProcesser;
import com.cndw.kungfu.ext.TimeProcesser;
import com.cndw.kungfu.model.WarWorldSerialize;
import com.cndw.kungfu.model.activity.domain.CrossServer;
import com.cndw.kungfu.model.battle.Battle;
import com.cndw.kungfu.model.pvp.api.WarApiClient;
import com.cndw.kungfu.model.pvp.api.ApiConfig;

public class WarWorldData implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private int cycle;
	
	/**
	 * 可以参加的玩家
	 */
	private Map<Long, WarPlayer> joinPlayers = new ConcurrentHashMap<Long, WarPlayer>();

	/**
	 * 胜出列表
	 */
	private Set<Long> winIds = new HashSet<Long>();

	/**
	 * 淘汰赛列表
	 */
	private transient static List<WarVs> vsList = new LinkedList<WarVs>();
	/**
	 * 记录失败的次数
	 */
	private transient static Map<Long, Integer> failNumMap = new ConcurrentSkipListMap<Long, Integer>();

	/**
	 * 每轮晋级还剩余多少人
	 */
	private Map<Integer, Integer> emtNums = new HashMap<Integer, Integer>();
	/**
	 * 临时记录战斗对象数据
	 */
	private static transient Map<Long, WarFighter> fighterMap = new ConcurrentHashMap<Long, WarFighter>();

	private static transient Set<Integer> sucSids = new HashSet<Integer>();

	/**
	 * 决赛列表
	 */
	private List<WarVs> orderVsList = new LinkedList<WarVs>();
	/**
	 * 胜出的玩家
	 */
	private ConcurrentHashMap<Integer, Map<Integer, Long>> winerMap = new ConcurrentHashMap<Integer, Map<Integer, Long>>();

	/**
	 * 玩家对应胜利的次数
	 */
	private Map<Long, Integer> winTimesMap = new ConcurrentHashMap<Long, Integer>();

	/**
	 * 下注列表
	 */
	private ConcurrentLinkedQueue<WarBet> bets = new ConcurrentLinkedQueue<WarBet>();

	/**
	 * 我的下注.对应的玩家
	 */
	private ConcurrentHashMap<Long, WarBet> betEasyMap = new ConcurrentHashMap<Long, WarBet>();
	/**
	 * 跨服数据抓取的状态
	 */
	private transient int crossState = 0;

	/**
	 * 当前比赛类型
	 */
	private int camType = 0;
	/**
	 * 当前进度
	 */
	private int step = 0;
	/**
	 * 淘汰赛轮次
	 */
	private int emtRund;
	/**
	 * 是否可下注
	 */
	private boolean bet;
	
	private transient static boolean haveDo = false;

	public WarWorldData() {
		cycle = WarConfig.getCycle();
	}

	public synchronized void clear() {
		joinPlayers.clear();
		winIds.clear();
		vsList.clear();
		failNumMap.clear();
		emtNums.clear();
		fighterMap.clear();
		sucSids.clear();		
		orderVsList.clear();		
		winerMap.clear();
		winTimesMap.clear();
		bets.clear();
		betEasyMap.clear();
		
		crossState = 0;
		camType = 0;
		step = 0;		
		emtRund = 0;
		bet = false;
		LogUtil.getMain().debug("war world clear "+cycle);
		cycle = WarConfig.getCycle();
		
		commitSync();
	}
	
	public void commitSync() {
		WarWorldSerialize.getInstance().commitSync();
	}

	public void addPlayer(WarPlayer warPlayer) {
		if (warPlayer.getPid() <= 0) {
			LogUtil.getMain().debug("err id");
		}
		joinPlayers.put(warPlayer.getPid(), warPlayer);
	}

	public boolean isJoin(long pid) {
		return joinPlayers.containsKey(pid);
	}

	public synchronized boolean crossReady() {
		if (crossState == 0) {

			Set<Integer> areIds = new HashSet<Integer>();
			Collection<CrossServer> servers = CrossServer.getAll();
			for (CrossServer e : servers) {
				if (e.getType() <= 0) {
					continue;
				}
				if (!areIds.contains(e.getType())) {
					areIds.add(e.getType());
					WarCrossData data = WarCoreCenter.getCrossData(e.getType());
					if (data != null) {
						List<WarPlayer> pro32 = data.getPlayersPro32();
						for (WarPlayer ew : pro32) {
							joinPlayers.put(ew.getPid(), ew);
						}
					}
				}
			}

			LogUtil.getMain().debug("joinPlayers.size " + joinPlayers.size());
			crossState = 1;
			WarEvent.runUpdateWorldScore();// 更新玩家战力

		}
		if (crossState == 1) {
			boolean over = true;
			for (WarPlayer e : joinPlayers.values()) {
				if (!fighterMap.containsKey(e.getPid())) {
					WarFighter fighter = WarApiClient.getWarFighter(e.getSid(), e.getPid());
					if (fighter != null) {
						fighterMap.put(e.getPid(), fighter);
					} else {
						over = false;
					}
				}
			}
			if (over) {
				crossState = 2;
				LogUtil.getMain().debug("got suc "+fighterMap.size());
			}
		}

		return crossState == 2;
	}

	public synchronized void checkCycle() {
		cycle = cycle == 0 ? 1 : cycle;
		if (cycle < WarConfig.getCycle()) {
			clear();
		}
	}

	protected synchronized void runBoss() {
		int tmpStep = step;
		int tmpCam = camType;
		if (vsList == null) {
			vsList = new LinkedList<WarVs>();
		}
		haveDo = false;
		int diff = TimeProcesser.getUnixTime() - WarConfig.getWorldBegin() - WarConfig.eliminateBegin;
		if (step == 0) {
			if (diff < 0) {
				return;
			}
			if (!crossReady()) {// 是否抓取完用户数据
				return;// 等待继续抓
			}
			if (joinPlayers.size() < 32) {
				step = 4;
				LogUtil.getMain().debug("game is not open ");
				commitSync();
				return;
			}
			processEliminate();
			step = 1;
			haveDo = true;
		}
		if (step == 1) {
			if (diff >= emtRund * WarConfig.emtOneTime) {
				camType = 32;
				processGot32();
				processPromotion();
				step = 2;
				haveDo = true;
			}
		} else if (step == 2) {
			if (prossVs()) {
				processPromotion();
				haveDo = true;
			}
		} else if (step == 4) {
			return;
		}
		if (tmpStep != step || tmpCam != camType) {
			LogUtil.getMain().debug("api cros step" + step + "->" + camType);
			WarCoreCenter.worldUpWarInfo(step, camType);
		}
		if (haveDo) {
			commitSync();
		}		
	}

	public synchronized void processEliminate() {

		LogUtil.getMain().debug("processEliminate");
		LogUtil.getMain().debug("appPlayerIds:" + joinPlayers.size());

		winIds.addAll(joinPlayers.keySet());
		while (winIds.size() > WarConfig.promotionMember) {
			emtRund++;
			assign();
			emtNums.put(emtRund, winIds.size());
			LogUtil.getMain().debug("emtRund:" + emtRund);
		}

		LogUtil.getMain().debug("appPlayerIds:" + joinPlayers.size());
		LogUtil.getMain().debug("winIds:" + winIds.size());
		LogUtil.getMain().debug("vsList:" + vsList.size());
	}

	public void assign() {
		List<Long> xxIds = new ArrayList<Long>(winIds);
		Collections.shuffle(xxIds);
		Iterator<Long> it = xxIds.iterator();
		while (it.hasNext()) {
			Long sourceId = (Long) it.next();
			if (it.hasNext()) {
				long targetId = it.next();
				int win = battle(sourceId, targetId, false);

				vsList.add(new WarVs(sourceId, targetId, win));

				if (win == 2) {
					signFail(sourceId);
				} else {
					signFail(targetId);
				}
				if (winIds.size() <= WarConfig.promotionMember) {// 低于32名退出
					break;
				}
			} else {

			}
		}

	}

	private void signFail(long playerId) {
		int faid = failNumMap.containsKey(playerId) ? failNumMap.get(playerId) : 0;
		faid++;
		failNumMap.put(playerId, faid);
		if (faid >= WarConfig.eliminateTimes) {
			winIds.remove(playerId);
		}
	}

	public void processGot32() {
		
		List<Long> tmpWins = new ArrayList<Long>(winIds);
		Collections.shuffle(tmpWins);
		
		WarPlayerCompartor comparator = new WarPlayerCompartor();
		TreeSet<WarPlayer> order = new TreeSet<WarPlayer>(comparator);
		
		StringBuilder sb = new StringBuilder();
		Iterator<Long> it = tmpWins.iterator();
		while (it.hasNext()) {
			Long long1 = (Long) it.next();
			WarPlayer warPlayer = joinPlayers.get(long1);
			if (warPlayer != null) {
				if (sb.length() > 0) {
					sb.append("、");
				}
				sb.append("S");
				sb.append(warPlayer.getSid());
				sb.append('.');
				sb.append(warPlayer.getPn());
				
				order.add(warPlayer);
			}else {
				LogUtil.getMain().error("no uid "+ long1);
			}
		}
		
		Map<Integer, Long> tmpIds = new LinkedHashMap<Integer, Long>();
		
		Map<Integer, Integer> orderIndex = WarConfig.makeFixOrderMap();	

		int orderId = 0;
		Iterator<WarPlayer> pit =order.iterator();
		while (pit.hasNext()) {
			WarPlayer warPlayer = (WarPlayer) pit.next();
			orderId ++ ;
			tmpIds.put(orderIndex.get(orderId), warPlayer.getPid());
		}
		
		winerMap.putIfAbsent(camType, tmpIds);
		chatMsssage(LanguageLib.get("war.pro.chat32", sb.toString()));
		
	}

	private void chatMsssage(String msg) {
		WarCoreCenter.chatMsssage(0, msg);
	}

	public void processPromotion() {
		if (winerMap.containsKey(camType)) {
			LogUtil.getMain().debug("camType:" + camType + " -> winerMap:" + winerMap.get(camType).size() + " " + orderVsList.size());

			Map<Integer, Long> winer = winerMap.get(camType);
			if (winer.size() == 1) {
				LogUtil.getMain().debug(" game is over ... boss is find ");
				step = 3;
				return;
			} else {
				// 分配比賽
				assignPromotion(winerMap.get(camType));
			}

		} else {
			LogUtil.getMain().debug("err .....");
			return;
		}

	}

	private void assignPromotion(Map<Integer, Long> winer) {

		List<Long[]> against = new LinkedList<Long[]>();

		int maxSize = winer.size() / 2;
		maxSize = camType / 2;
		int orderId = 0;
		for (int i = 0; i < maxSize; i++) {
			orderId++;
			int numFirst = i * 2 + 1;
			int numScond = i * 2 + 2;
			if (winer.containsKey(numFirst) && winer.containsKey(numScond)) {
				against.add(new Long[] { winer.get(numFirst), winer.get(numScond) });
			} else {
				if (winer.containsKey(numFirst)) {
					proNext(maxSize, winer.get(numFirst), orderId, 0);
					LogUtil.getMain().debug("fast to promotion " + winer.get(numFirst));
				}
			}
		}

		LogUtil.getMain().debug("against" + against.size() + " " + orderId);
		if (against.size() > 0) {
			for (int i = 0; i < 5; i++) {
				for (Long[] longs : against) {
					WarVs vs = new WarVs();
					if (NumberProcesser.isWinning(50)) {
						vs.setS(longs[1]);
						vs.setT(longs[0]);
					}else {
						vs.setS(longs[0]);
						vs.setT(longs[1]);
					}		
					vs.setC(camType);
					vs.setO(i);
					orderVsList.add(vs);
				}
			}
		}
		bet = true;
		LogUtil.getMain().debug("orderVsList" + orderVsList.size());
		winTimesMap.clear();
	}

	public boolean prossVs() {
		Iterator<WarVs> list = orderVsList.iterator();
		int num = 0;

		int diff = TimeProcesser.getUnixTime() - WarConfig.getWorldBegin();

		boolean faild = false;
		while (list.hasNext()) {
			WarVs warVs = (WarVs) list.next();
			if (warVs.getW() == 0) {
				if (diff < WarConfig.camStartTime.get(warVs.getC()) + warVs.getO() * 1800) {
					return false;
				}
				haveDo = true;
				bet = false;
				num++;
				int win = battle(warVs.getS(), warVs.getT(), false);
				if (win < 0) {
					faild = true;
					LogUtil.getMain().debug("err call no player ");
					continue;
				}
				warVs.setW(win);
				checkPromotion(win == 1 ? warVs.getS() : warVs.getT(), win == 1 ? warVs.getT() : warVs.getS());
			} else {

			}
		}
		if (faild) {
			return false;
		}
		LogUtil.getMain().debug("pross vs : " + num);
		camType /= 2;
		return true;
	}

	private void checkPromotion(long winId, long lostId) {
		int cTimes = winTimesMap.containsKey(winId) ? winTimesMap.get(winId) : 0;
		cTimes++;
		winTimesMap.put(winId, cTimes);
		if (cTimes == 3) {
			Map<Integer, Long> winMap = winerMap.get(camType);
			for (Map.Entry<Integer, Long> entry : winMap.entrySet()) {
				if (entry.getValue() == winId) {
					proNext(camType / 2, winId, (entry.getKey() + 1) / 2, lostId);
					break;
				}
			}
		}
	}

	/**
	 * 是否发过奖励
	 */
	private static transient Map<Long, Boolean> awardMap = new HashMap<Long, Boolean>();

	private String makeCN(WarPlayer warPlayer) {
		StringBuilder sb = new StringBuilder();
		sb.append('S').append(warPlayer.getSid()).append('.');
		sb.append(warPlayer.getPn());
		return sb.toString();
	}

	private void proNext(int camType, long winId, int orderId, long lostId) {
		if (!winerMap.containsKey(camType)) {
			winerMap.putIfAbsent(camType, new LinkedHashMap<Integer, Long>());
		}
		if (winerMap.get(camType).containsKey(orderId)) {
			LogUtil.getMain().error("exits in here ." + orderId + "c: " + camType + " w:" + winId);
		}
		LogUtil.getMain().debug("camType " + camType + " orderId " + orderId + " winId " + winId);
		winerMap.get(camType).put(orderId, winId);
		if (lostId == 0) {
			return;
		}
		WarPlayer source = getWarPlayer(winId);
		WarPlayer target = getWarPlayer(lostId);
		if (lostId > 0 && !awardMap.containsKey(lostId)) {
			sendAward(target.getSid(), lostId, camType * 2);
		}
		if (camType == 1 && !awardMap.containsKey(winId)) {
			sendAward(source.getSid(), winId, camType);
		}

		chatMsssage(LanguageLib.get("war.pro.chat" + camType, makeCN(source), makeCN(target)));

		Iterator<WarBet> it = bets.iterator();
		while (it.hasNext()) {
			WarBet warBet = (WarBet) it.next();
			if (warBet.getW() > 0 || warBet.getC() != camType * 2) {
				continue;
			}
			if (warBet.getT() != winId && warBet.getT() != lostId) {
				continue;
			}
			WarPlayer player = getWarPlayer(warBet.getT());
			if (player == null) {
				continue;
			}
			boolean suc = warBet.getT() == winId;
			int asset = 0;
			if (warBet.getT() == winId) {
				warBet.setW(1);
				asset = warBet.getAsset() * 2;
			} else {
				warBet.setW(2);
			}
			String content = LanguageLib.get(warBet.getW() == 1 ? "war.bet.suc" : "war.bet.fail", makeCN(source), makeCN(target));

			sendBetMsg(warBet.getX(), warBet.getS(), warBet.getC(), suc, asset, content);

		}
	}

	private void sendBetMsg(int serverId, long uid, int camType, boolean suc, int asset, String content) {
		WarCoreCenter.sendBetMsg(serverId, 3, uid, camType, suc, asset, content);
	}

	private void sendAward(int serverId, long uid, int camType) {
		WarCoreCenter.worldSendAward(serverId, uid, camType);
		awardMap.put(uid, true);
	}

	private WarFighter getWarFighter(long sourceId, boolean immediate) {
		if (immediate && fighterMap.containsKey(sourceId)) {
			return fighterMap.get(sourceId);
		}
		WarPlayer warPlayer = joinPlayers.get(sourceId);
		WarFighter warFighter = WarApiClient.getWarFighter(warPlayer.getSid(), warPlayer.getPid());
		return warFighter;
	}

	private int battle(long sourceId, long targetId, boolean immediate) {
		WarFighter source = getWarFighter(sourceId, immediate);
		WarFighter target = getWarFighter(targetId, immediate);
		if (source == null || target == null) {
			LogUtil.getMain().error("err " + sourceId + " : " + targetId);
			return -1;
		}
		source.fullHpAndMp();
		target.fullHpAndMp();

		Battle battle = new Battle(source, target);
		battle.execBattle(Constants.battle_pvpCross);
		battle.clear();
		return battle.getWiner() == 1 ? 1 : 2;
	}

	public boolean isBet() {
		return bet;
	}

	public int getStep() {
		return step;
	}

	public boolean isProm() {
		return TimeProcesser.getUnixTime() >= WarConfig.getWorldBegin() + WarConfig.eliminateBegin + emtRund * 300;
	}

	public Iterator<WarVs> getVsIterator() {
		return vsList.iterator();
	}

	public WarPlayer getWarPlayer(long t) {
		return joinPlayers.get(t);
	}

	public Map<Integer, Map<Integer, Long>> getWinerMap() {
		return winerMap;
	}

	public int getCamType() {
		return camType;
	}

	public Object getEmtNum(int k) {
		return emtNums.containsKey(k) ? emtNums.get(k) : 0;
	}

	public Iterator<WarVs> getOrderVsList() {
		return orderVsList.iterator();
	}

	public Object getOrderPower() {
		WarPlayerCompartor comparator = new WarPlayerCompartor();
		TreeSet<WarPlayer> order = new TreeSet<WarPlayer>(comparator);
		order.addAll(joinPlayers.values());
		List<WarPlayer> orderPlayers = new ArrayList<WarPlayer>();
		int i = 0;
		for (WarPlayer e : order) {
			i++;
			orderPlayers.add(e);
			if (i >= 100) {
				break;
			}
		}

		return orderPlayers;
	}

	public WarBet betAsset(int camType2, int x, long uid, long targetId, int asset) {
		WarBet warBet = new WarBet();
		warBet.setAsset(asset);
		warBet.setC(camType2);
		warBet.setX(x);
		warBet.setS(uid);
		warBet.setT(targetId);
		bets.add(warBet);
		betEasyMap.put(uid, warBet);
		return warBet;
	}

	public WarBet betGet(long uid) {
		return betEasyMap.get(uid);
	}

	public Iterator<WarBet> getBets() {
		return bets.iterator();
	}
	
	

	public int getEmtRund() {
		return emtRund;
	}

	public WarPlayer getBoss() {
		if (winerMap.containsKey(1) && winerMap.get(1).containsKey(1)) {
			long t = winerMap.get(1).get(1);
			return getWarPlayer(t);
		}
		return null;
	}

	public void updateScoreEvent() {
		synchronized (WarEvent.class) {
			Collection<WarPlayer> allPlayers = joinPlayers.values();
			for (WarPlayer e : allPlayers) {
				Object m = WarApiClient.sendApiByTimeOut(e.getSid(), ApiConfig.warPlayer, 2000, e.getPid());
				if (m != null && m instanceof WarPlayer) {
					WarPlayer mPlayer = (WarPlayer) m;
					e.setPp(mPlayer.getPp());
				}

			}
		}

	}

}
